import sys
from psutil import net_connections
import logging
import os
import time
import subprocess
import socket

basedir = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, basedir)

log = logging.getLogger(__name__)

formatter = logging.basicConfig(filename="{}/{}".format(basedir, 'transfer.log'),
                                level=logging.DEBUG,
                                format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                                datefmt='%a, %d %b %Y %H:%M:%S')
logging.getLogger("pika").propagate = False

from info_config import instance_port
from info_config import ip_connect_filter
# from info_config import service_name
from info_config import service_exporter_name
from info_config import instance_port_check_connect_times
from info_config import instance_port_check_connect_interval
from info_config import data_directory
from info_config import install_directory
from info_config import instance_host
from info_config import instance_offline_procedure_into_pt_url
from info_config import offline_result_into_pt_url

now_time = time.strftime("%Y%m%d%H%M%S", time.localtime())

from dbpt_utils import info_interactive_with_dbpt


def run_cmd(cmd, information=None, file_output=None):
    """
    执行命令并发送初始信息给mq
    :param cmd: 执行的备份命令
    :param information: 备份信息实例
    :param file_output: 文件输出
    :return:
    """
    log.debug(cmd)
    # return 0
    if file_output is None:
        stdout = subprocess.PIPE
        stderr = subprocess.STDOUT
    else:
        stdout = file_output
        stderr = file_output
    p = subprocess.Popen(cmd,
                         shell=True,
                         stdout=stdout,
                         stderr=stderr)
    pid = p.pid
    try:
        information.set_pid_info(pid=pid)
        information.backup_startup_publish()
    except AttributeError as e:
        pass
    # result = p.stdout.read()
    return_code = p.wait()
    return return_code


def port_connect_check(port):
    port_connect = net_connections()

    # print(port_connect)
    def judge_conn(conn):
        # if conn.status == "ESTABLISHED":
        if conn.status == "ESTABLISHED" and conn.laddr[1] == port:
            for i in ip_connect_filter:
                if i == conn.raddr[0]:
                    return False
            return True

    raddr_list = []
    for conn in port_connect:
        if judge_conn(conn):
            raddr_list.append(conn.raddr[0])
    return set(raddr_list)


def judge_port(port):
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        return s.connect_ex(('localhost', port)) == 0


def directory_rename(directory_to_rename):
    if directory_to_rename is None:
        return 1
    destination_directory = directory_to_rename.rstrip('/') + "_backup_" + now_time
    # destination_directory = '/'.join(_destination_directory) + "/../"
    # destination_directory = _destination_directory.join('/')
    print(destination_directory)
    try:
        os.rename(directory_to_rename, destination_directory)
        return 0
    except Exception:
        return 1


def offline_procedure_info_into_pt(procedure_info):
    procedure_info = {"instance_port": instance_port, "procedure_info": procedure_info, "instance_host": instance_host}
    return info_interactive_with_dbpt(suffix_url=instance_offline_procedure_into_pt_url, args_send=procedure_info)


def offline_result_into_pt(**kwargs):
    result_info = kwargs.get('result_info')
    offline_result = kwargs.get('offline_result')
    off_line_result = {"instance_port": instance_port, "result_info": result_info, "instance_host": instance_host,
                       "offline_result": offline_result}
    return info_interactive_with_dbpt(suffix_url=offline_result_into_pt_url, args_send=off_line_result)


def main():
    offline_procedure_info_into_pt("检查实例连接情况")
    for i in range(instance_port_check_connect_times):
        connect_host = port_connect_check(instance_port)
        if not connect_host:
            time.sleep(instance_port_check_connect_interval)
        else:
            log.error("检测到仍然有集群外其它主机在连接({connect_host}),现退出;或修改info_config.py中ip_connect_filter项重新执行下线脚本.".format(
                connect_host=str(connect_host)))
            offline_result_into_pt(result_info='实例下线失败，检查到有应用或其它连接(%s).' % str(connect_host),
                                   offline_result=1)
            return 1
    # instance_service_name = "%s%s" % (service_name, instance_port)
    # instance_service_stop_command = "service %s stop" % instance_service_name
    # disable_instance_service_command = "systemctl disable %s" % instance_service_name
    # offline_procedure_info_into_pt("正在关停实例")
    # return_code = run_cmd(instance_service_stop_command)
    # if return_code == 0:
    #     offline_procedure_info_into_pt("取消实例开机启动")
    #     run_cmd(disable_instance_service_command)
    for exporter_name in service_exporter_name:
        exporter_service_command = "service %s stop" % exporter_name
        disable_exporter_service_command = "systemctl disable %s" % exporter_name
        offline_procedure_info_into_pt("正在执行:{}".format(exporter_service_command))
        run_cmd(exporter_service_command)
        offline_procedure_info_into_pt("正在执行:{}".format(disable_exporter_service_command))
        run_cmd(disable_exporter_service_command)

        if judge_port(port=instance_port) == 0:
            offline_procedure_info_into_pt("修改实例数据目录(如有需要)")
            directory_rename(data_directory)
            offline_procedure_info_into_pt("修改实例安装目录(如有需要)")
            directory_rename(install_directory)
            # offline_procedure_info_into_pt("关停相关exporter")
            # for exporter_name in service_exporter_name:
            #     exporter_service_command = "service %s stop" % exporter_name
            #     disable_exporter_service_command = "systemctl disable %s" % exporter_name
            #     run_cmd(exporter_service_command)
            #     run_cmd(disable_exporter_service_command)
            offline_result_into_pt(result_info='实例下线完成', offline_result=0)


if __name__ == "__main__":
    sys.exit(main())
